package com.topvision.myviewtest.camera;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.ErrorCallback;
import android.hardware.Camera.PreviewCallback;
import android.os.Build;
import android.os.SystemClock;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

import java.util.List;

class CameraPreview extends SurfaceView implements ErrorCallback, SurfaceHolder.Callback, PreviewCallback {
    private static final int ERROR_100 = 100;
    private boolean mIsCameraOpen;
    private int iDecAttempt = 1;
    private CameraManager cameraMgr;
    private Context context;
    private SurfaceHolder surfaceHolder;
    private OnPreviewCallback mPreviewCallback;

    public CameraPreview(Context context) {
        super(context);
        this.context = context;
        instantiateSurface();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        surfaceHolder = holder;
        startCamera();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        LogUtil.trace();
        WindowManager winManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        cameraMgr.adjustCameraDisplayOrientation(winManager != null ? winManager.getDefaultDisplay().getRotation() : 0);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        destroySurface();
    }

    public void startCamera() {
        instantiateSurface();
        createSurface();
    }

    public void stopCamera() {
        CameraManager.destroyInstance();
    }

    public void pauseCamera() {
        if (cameraMgr != null) {
            cameraMgr.getCamera().stopPreview();
        }
    }

    public void resumeCamera() {
        if (cameraMgr != null) {
            cameraMgr.getCamera().startPreview();
        }
    }

    private void instantiateSurface() {
        LogUtil.trace();
        try {
            cameraMgr = CameraManager.getInstance(context);
            cameraMgr.openCamera();
            SurfaceHolder holder = getHolder();
            holder.addCallback(this);
            holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        } catch (Exception e) {
            LogUtil.e(e);
        }

    }

    private void createSurface() {
        try {
            if (initializeCamera(surfaceHolder)) {
                cameraMgr.getCamera().addCallbackBuffer(cameraMgr.previewBuffer);
                cameraMgr.getCamera().setPreviewCallbackWithBuffer(this);
            }
        } catch (Exception e) {
            LogUtil.e(e);
        }
    }

    private void destroySurface() {
        LogUtil.trace();
        try {
            if (cameraMgr.isCameraOpen()) {
                cameraMgr.killAutofocus();
                if (!Build.MODEL.equals("C771")) {
                    cameraMgr.getCamera().stopPreview();
                }
                cameraMgr.closeCamera();
            }
        } catch (Exception e) {
            LogUtil.e(e);
        }

    }

    private Boolean initializeCamera(SurfaceHolder holder) {
        LogUtil.trace();
        try {
            mIsCameraOpen = true;
            cameraMgr.getCamera().setErrorCallback(this);
            cameraMgr.getCamera().setPreviewDisplay(holder);
            cameraMgr.getCamera().startPreview();
            return true;
        } catch (Exception e) {
            LogUtil.e(e);
            return false;
        }
    }

    private void focusIfRequired(boolean lastScanResult) {
        try {
            if (!mIsCameraOpen || !cameraMgr.isAutoFocusSupported) {
                return;
            }

            if (++iDecAttempt >= cameraMgr.getDecoderAttemptsPerAFCycle() && !lastScanResult) {
                iDecAttempt = 0;
                foucusFlag = true;
                cameraMgr.getCamera().autoFocus(mAutoFocusCallback);
            }
        } catch (Exception e) {
            LogUtil.e(e);
        }
    }


    private boolean foucusFlag;
    AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            camera.cancelAutoFocus();
            Camera.Parameters parameters = camera.getParameters();
            String currentFocusMode = parameters.getFocusMode();
            System.out.println("currentFocusMode: " + currentFocusMode);
            if (success
                    && !Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO.equals(currentFocusMode)
                    && !Build.MODEL.contains("BT")) {
                cameraMgr.isAutoFocusSupported = false;
                SystemClock.sleep(200);
                List<String> focusModes = parameters.getSupportedFocusModes();
                for (String focusMode : focusModes) {
                    System.out.println(focusMode);
                    if (focusMode.equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
                        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
                        camera.setParameters(parameters);
                        System.out.println("设置对焦模式: " + focusMode);
                        break;
                    }
                }
            }
            foucusFlag = false;
        }
    };

    @Override
    public void onError(int error, Camera camera) {
        LogUtil.e("ERROR: " + error);
        if (error == ERROR_100) {
            cameraMgr.reopenCamera();
        }
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        if (camera == null || data == null) return;
        focusIfRequired(foucusFlag);
        if (mPreviewCallback != null) {
            mPreviewCallback.onPreviewFrame(data, camera);
        }
        // 取下一帧
        try {
            cameraMgr.getCamera().addCallbackBuffer(cameraMgr.previewBuffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置相机变焦
     */
    public void setZoom(int stepZoom, boolean isAdd) {
        if (cameraMgr.getCamera() != null) {
            Camera.Parameters parameters = cameraMgr.getCamera().getParameters();
            int maxZoomValue = parameters.getMaxZoom();
            int defZoomValue = parameters.getZoom();
            int zoomValue;
            if (isAdd) {
                zoomValue = defZoomValue + stepZoom;
            } else {
                zoomValue = defZoomValue - stepZoom;
            }
            if (zoomValue > maxZoomValue) {
                zoomValue = maxZoomValue;
            } else if (zoomValue < 0) {
                zoomValue = 0;
            }
            if (zoomValue != defZoomValue) {
                if (parameters.isZoomSupported() && parameters.isSmoothZoomSupported()) {
                    cameraMgr.getCamera().startSmoothZoom(zoomValue);
                } else if (parameters.isZoomSupported() && !parameters.isSmoothZoomSupported()) {
                    parameters.setZoom(zoomValue);
                    cameraMgr.getCamera().setParameters(parameters);
                } else {
                    Log.e("CameraPreview", "setZoom: 该设备不支持变焦");
                }
            }
        }
    }

    /**
     * 外部调用函数
     */
    public void setPreviewCallback(OnPreviewCallback previewCallback) {
        mPreviewCallback = previewCallback;
    }

    public Camera getCamera() {
        return cameraMgr == null ? null : cameraMgr.getCamera();
    }
}
